import { Request, Response } from 'express';
import fs from 'fs/promises';
import { createReadStream, existsSync } from 'fs';
import { createInterface } from 'readline';
import path from 'path';
import { NginxUtil } from '../utils/nginx.util';
import { ConfigModel } from '../models/Config';
import { reverseReadLines } from '../utils/fileStorage';

// 月份名称到数字的映射
const months: { [key: string]: string } = {
  'Jan': '01', 'Feb': '02', 'Mar': '03', 'Apr': '04',
  'May': '05', 'Jun': '06', 'Jul': '07', 'Aug': '08',
  'Sep': '09', 'Oct': '10', 'Nov': '11', 'Dec': '12'
};

// Nginx 日志正则表达式
const NGINX_LOG_PATTERN = /^(\S+) - - \[([\d\/\w:]+\s[+\-]\d{4})\] "([^"]*)" (\d{3}) (\d+) "([^"]*)" "([^"]*)"\r?$/;

// 日志分析结果接口
interface LogAnalysis {
  totalRequests: number;
  successRequests: number;
  errorRequests: number;
  statusCodes: { [key: string]: number };
  topIPs: { [key: string]: number };
  topURLs: { [key: string]: number };
  avgResponseTime: number;
  totalResponseTime: number;
  topMethods: { [key: string]: number };
  topUserAgents: { [key: string]: number };
  avgResponseSize: number;
  totalResponseSize: number;
}

export class LogController {
  // 获取日志文件列表（内部使用）
  private static async getLogFilesInternal(): Promise<Array<{ name: string; path: string; size: number; modified: Date }>> {
    // 获取 Nginx 配置信息
    const logPaths = await NginxUtil.getAllLogPaths();
    console.log('logPaths', logPaths);
    const validFiles = await Promise.all(Array.from(logPaths).map(async (p: string) => {
      const filePath = p.trim();
      const stats = await fs.stat(filePath);
      return {
        name: path.basename(filePath),
        path: filePath,
        size: stats.size,
        modified: stats.mtime
      };
    }));

    return validFiles;
  }

  // 获取日志文件列表（API 端点）
  static async getLogFiles(req: Request, res: Response) {
    try {
      const files = await LogController.getLogFilesInternal();
      res.json(files);
    } catch (error) {
      console.error('Failed to get log files:', error);
      res.status(500).json({ message: error instanceof Error ? error.message : '获取日志文件列表失败' });
    }
  }

  // 读取日志文件内容（支持分页和实时）
  static async readLogFile(req: Request, res: Response) {
    try {
      const { filePath } = req.params;
      const { lines = 100, tail = false } = req.query;

      const config = await ConfigModel.getSystemConfig();
      if (!config) {
        return res.status(400).json({ message: '请先配置 Nginx' });
      }

      // Docker 环境下进行路径映射
      let targetPath = filePath;
      if (config.isDockerized && config.dockerHostLogPath && config.dockerContainerLogPath) {
        if (filePath.startsWith(config.dockerContainerLogPath)) {
          const relativePath = path.relative(config.dockerContainerLogPath, filePath);
          targetPath = path.join(config.dockerHostLogPath, relativePath);
          console.log('Mapped Docker log path:', { 
            original: filePath, 
            mapped: targetPath 
          });
        }
      }

      if(!existsSync(targetPath)) {
        return res.status(404).json({ message: '日志文件不存在' });
      }

      const numLines = parseInt(lines as string);
      if (isNaN(numLines) || numLines <= 0) {
        return res.status(400).json({ message: '无效的行数参数' });
      }

      if (tail) {
        // 从文件末尾读取指定行数
        const logLines: string[] = [];
        const fileStream = createReadStream(targetPath);
        const rl = createInterface({
          input: fileStream,
          crlfDelay: Infinity
        });

        for await (const line of rl) {
          logLines.push(line);
          if (logLines.length > numLines) {
            logLines.shift();
          }
        }

        res.json({ lines: logLines, filePath: targetPath });
      } else {
        // 读取整个文件
        const content = await fs.readFile(targetPath, 'utf-8');
        const allLines = content.split('\n');
        const startLine = Math.max(0, allLines.length - numLines);
        const selectedLines = allLines.slice(startLine);

        res.json({ lines: selectedLines, filePath: targetPath });
      }
    } catch (error) {
      console.error('读取日志文件失败:', error);
      res.status(500).json({ message: '读取日志文件失败' });
    }
  }

  // 添加新的逆向读取日志的函数
  static async analyzeLogReverse(filePath: string, startTime: Date): Promise<LogAnalysis> {
    const result: LogAnalysis = {
      totalRequests: 0,
      successRequests: 0,
      errorRequests: 0,
      statusCodes: {},
      topIPs: {},
      topURLs: {},
      avgResponseTime: 0,
      totalResponseTime: 0,
      topMethods: {},
      topUserAgents: {},
      avgResponseSize: 0,
      totalResponseSize: 0
    };

    console.log('start time', startTime.toLocaleString());
    console.log('filePath', filePath);

    try {
      const lines = reverseReadLines(filePath);
      
      for await (const line of lines) {
        if (!line.trim()) continue;
        console.log('line', line);
        const matches = line.match(NGINX_LOG_PATTERN);
        if (!matches) {
          console.log('Failed to parse line:', line);
          // 调试输出，帮助定位问题
          console.log('Line parts:', {
            full: line,
            ip: line.match(/^(\S+)/)?.[1],
            timestamp: line.match(/\[([\d\/\w:]+\s[+\-]\d{4})\]/)?.[1],
            request: line.match(/"([^"]*)"/)?.[1],
            status: line.match(/" (\d{3}) /)?.[1],
            bytes: line.match(/ (\d+) "/)?.[1],
            referer: line.match(/ "([^"]*)" "/)?.[1],
            userAgent: line.match(/" "([^"]*)"(?:\r)?$/)?.[1]
          });
          continue;
        }

        const [
          ,
          ip,
          timestamp,
          request,
          status,
          bytes,
          referer,
          userAgent
        ] = matches;

        // 尝试解析请求部分
        let method = '-', path = '-', protocol = '-';
        const requestMatch = request.match(/^([A-Z]+) ([^\s]+) (HTTP\/[\d.]+)$/);
        if (requestMatch) {
          [, method, path, protocol] = requestMatch;
        }

        // 解析时间
        try {
          const parts = timestamp.match(/(\d+)\/(\w+)\/(\d+):(\d+):(\d+):(\d+)\s+([+\-]\d{4})/);
          if (!parts) {
            console.log('Failed to parse timestamp:', timestamp);
            continue;
          }

          const [, day, month, year, hours, minutes, seconds, timezone] = parts;
          const monthNum = months[month];
          if (!monthNum) {
            console.log('Invalid month in timestamp:', timestamp);
            continue;
          }

          const formattedTime = `${hours.padStart(2, '0')}:${minutes.padStart(2, '0')}:${seconds.padStart(2, '0')}`;
          const formattedTimezone = timezone.replace(/([+-])(\d{2})(\d{2})/, '$1$2:$3');
          const isoString = `${year}-${monthNum}-${day.padStart(2, '0')}T${formattedTime}${formattedTimezone}`;
          const logTime = new Date(isoString);

          console.log('logTime ', logTime.toLocaleString(), 'startTime', startTime.toLocaleString());

          if (isNaN(logTime.getTime())) {
            console.log('Invalid date:', isoString);
            continue;
          }

          // 如果日志时间早于开始时间，说明已经读取完需要的部分，可以停止
          if (logTime < startTime) {
            console.log('Reached logs before start time, stopping analysis');
            break;
          }

          // 更新统计信息
          result.totalRequests++;
          
          // 状态码统计
          result.statusCodes[status] = (result.statusCodes[status] || 0) + 1;
          
          // 成功/失败请求统计
          if (status.startsWith('2')) {
            result.successRequests++;
          } else if (status.startsWith('4') || status.startsWith('5')) {
            result.errorRequests++;
          }
          
          // IP 统计
          result.topIPs[ip] = (result.topIPs[ip] || 0) + 1;
          
          // URL 统计（去除查询参数）
          if (path !== '-') {
            const url = path.split('?')[0];
            result.topURLs[url] = (result.topURLs[url] || 0) + 1;
          }

          // HTTP 方法统计
          if (method !== '-') {
            result.topMethods[method] = (result.topMethods[method] || 0) + 1;
          }

          // User Agent 统计
          if (userAgent !== '-') {
            result.topUserAgents[userAgent] = (result.topUserAgents[userAgent] || 0) + 1;
          }

          // 响应大小统计
          const responseSize = parseInt(bytes);
          if (!isNaN(responseSize)) {
            result.totalResponseSize += responseSize;
          }

        } catch (error) {
          console.error('Error processing log entry:', error);
          continue;
        }
      }

      // 计算平均响应大小
      if (result.totalRequests > 0) {
        result.avgResponseSize = Math.round(result.totalResponseSize / result.totalRequests);
      }

      // 对统计结果进行排序并限制数量
      const limitEntries = (obj: Record<string, number>, limit = 10) => {
        return Object.fromEntries(
          Object.entries(obj)
            .sort(([, a], [, b]) => (b as number) - (a as number))
            .slice(0, limit)
        );
      };

      result.topIPs = limitEntries(result.topIPs);
      result.topURLs = limitEntries(result.topURLs);
      result.topMethods = limitEntries(result.topMethods);
      result.topUserAgents = limitEntries(result.topUserAgents, 5);  // 限制 User Agent 数量为 5

      return result;
    } catch (error) {
      console.error('Error analyzing log file:', error);
      throw error;
    }
  }

  // 修改原有的路由处理函数
  static async analyzeLogs(req: Request, res: Response) {
    try {
      const { period = '24h' } = req.query;
      const { filePath } = req.params;
      
      // 计算开始时间
      const startTime = new Date();
      switch (period) {
        case '1h':
          startTime.setHours(startTime.getHours() - 1);
          console.log('startTime ----------- ', startTime.toLocaleString());
          break;
        case '24h':
          startTime.setDate(startTime.getDate() - 1);
          break;
        case '7d':
          startTime.setDate(startTime.getDate() - 7);
          break;
        default:
          return res.status(400).json({ error: 'Invalid time range' });
      }

      if (!existsSync(filePath)) {
        return res.status(404).json({ error: 'Access log file not found' });
      }

      const analysis = await LogController.analyzeLogReverse(filePath, startTime);
      res.json(analysis);
    } catch (error) {
      console.error('Error in analyzeLogs:', error);
      res.status(500).json({ error: 'Failed to analyze logs' });
    }
  }
} 